package threadjuc;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author zxl
 * @version 1.0
 * @date 2021/10/29 15:09
 * 自旋锁
 */
public class Juc17 {
    /**
     * 自旋锁（spinlock）：是指当一个线程在获取锁的时候，如果锁已经被其它线程获取，那么该线程将循环等待，然后不断的判断锁是否能够被成功获取，
     * 直到获取到锁才会退出循环。
     *
     * lock()方法利用的CAS，当第一个线程A获取锁的时候，能够成功获取到，不会进入while循环，如果此时线程A没有释放锁，另一个线程B又来获取锁，
     * 此时由于不满足CAS，所以就会进入while循环，不断判断是否满足CAS，直到A线程调用unlock方法释放了该锁。
     */

    /**
     * 默认为null   期望为null
     * 当地一个线程置换后将这个改成了不为空，第二个线程进来就会在while里循环，当第一个线程解锁后，又将这个改为了null 第二个线程就退出了循环
      */
    private AtomicReference<Thread> cas = new AtomicReference();

    public void lock() {
        Thread current = Thread.currentThread();
        System.out.println(current.getName() + "进来了");
         // 利用CAS 让下一个进来的线程循环等待
        while (!cas.compareAndSet(null, current)) {
         // DO nothing
            System.out.println(current.getName()+"等待");
        }

    }

    public void unlock() {
        Thread current = Thread.currentThread();
        cas.compareAndSet(current, null);
        System.out.println(current.getName()+"释放");
    }



    public static void main(String[] args) throws InterruptedException {
        Juc17 juc17 = new Juc17();

        new Thread(()->{
            juc17.lock();
            try{
                System.out.println("BB");
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                juc17.unlock();
            }
        },"a").start();

        TimeUnit.SECONDS.sleep(2);

        new Thread(()->{
            juc17.lock();
            try{
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                juc17.unlock();
            }
        },"b").start();
    }

}
